﻿using System;
using MPI;
using System.Collections;
using System.Collections.Generic;
using Baseballdata.Context;
using Baseballdata.Data;
using System.Data.Linq;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
    class Program
    {
        private double getStd(List<double> dbList)
        {
            double avg = dbList.Average();
            double sumOfDev = 0;
            foreach (double value in dbList)
            {
                sumOfDev += (value) * (value);
            }
            double soda = sumOfDev / dbList.Count;
            return Math.Sqrt(soda - (avg * avg));
        }

        private double getMean(List<double> dbLst)
        {
            double mean = 0;
            foreach (double average in dbLst)
            {
                mean += average;
            }
            mean /= dbLst.Count;
            return mean;
        }

        private double getZScore(double stats, double mean, double std)
        {

            double zScore = 0;
            zScore = ((stats - mean) / std);

            return zScore;
        }
        private Dictionary<string, double> SortDictionary(Dictionary<string, double> data)
        {
            List<KeyValuePair<string, double>> result =
                  new List<KeyValuePair<string, double>>(data);
            result.Sort(
              delegate(
                KeyValuePair<string, double> first,
                KeyValuePair<string, double> second)
              {
                  return second.Value.CompareTo(first.Value);
              }
              );
            return data;
        }

        static void Main(string[] args)
        {
            using (new MPI.Environment(ref args))
            {
                Intracommunicator comm = Communicator.world;
                Program newPrg = new Program();
                List<double> hofDbls = new List<double>();
                List<double> nhofDbls = new List<double>();


                List<double> hofTrips = new List<double>();
                List<double> nhofTrips = new List<double>();

                List<double> hofHits = new List<double>();
                List<double> nhofHits = new List<double>();

                List<double> hofABS = new List<double>();
                List<double> nhofABS = new List<double>();

                List<double> hofHRS = new List<double>();
                List<double> nhofHRS = new List<double>();

                List<double> hofRuns = new List<double>();
                List<double> nhofRuns = new List<double>();

                List<double> hofRBIS = new List<double>();
                List<double> nhofRBIS = new List<double>();

                List<double> hofSBS = new List<double>();
                List<double> nhofSBS = new List<double>();

                List<double> hofAVG = new List<double>();
                List<double> nhofAVG = new List<double>();

                List<double> nwDls = new List<double>();
                List<double> nnwDls = new List<double>();

                double zValueDoubles = 0;
                double zValueTrips = 0;
                double zValueHits = 0;
                double zValueABS = 0;
                double zValueHRS = 0;
                double zValueRuns = 0;
                double zValueRBIS = 0;
                double zValueSBS = 0;
                double zValueAVG = 0;
                string hofPlayerid = null;

                Dictionary<string, double> zscore = new Dictionary<string, double>();



                //Console.WriteLine("Enter Id: ");
                //hofPlayerid = Console.ReadLine();
                BaseballdataDataContext db = new BaseballdataDataContext();
                var results = from hof in db.HallOfFames
                              where hof.hofID == hofPlayerid
                              select hof;
                Console.WriteLine("start printing-------------");
                foreach (var q in results)
                {
                    Console.WriteLine("{0},{1}", q.hofID.Trim(), q.inducted);
                }
                Console.WriteLine("end printing--------");
                //Start
                DateTime startTime = DateTime.Now;
                var rslt = from hof in db.HallOfFames
                           where hof.inducted.Equals('Y') && hof.category == "Player"
                           //&& hof.hofID == hofPlayerid
                           select hof;

                Console.WriteLine("start calculations For HOF players---------");
                var count = 0;
                foreach (var q in rslt)
                {
                    var fld = (from f in db.Fieldings
                               join m in db.Masters on f.playerID equals m.playerID
                               where (!f.POS.Equals('P') && q.hofID == m.hofID)
                               orderby f.playerID ascending
                               group f by f.playerID into field
                               where field.Count() > 10
                               select new
                               {
                                   Id = field.Key
                               }).Distinct();
                    foreach (var n in fld)
                    {
                        var master = from b in db.Battings
                                     join m in db.Masters on b.playerID equals m.playerID
                                     where (n.Id == b.playerID)
                                     group b by b.playerID into batting
                                     //&& hof.hofID == hofPlayerid
                                     select new
                                     {
                                         Id = batting.Key,
                                         Doubles = batting.Average(i => i._2B),
                                         Triples = batting.Average(i2 => i2._3B),
                                         Hits = batting.Average(i3 => i3.H),
                                         AB = batting.Average(i8 => i8.AB),
                                         HomeRuns = batting.Average(i4 => i4.HR),
                                         Runs = batting.Average(i5 => i5.R),
                                         RBI = batting.Average(i6 => i6.RBI),
                                         StolenBases = batting.Average(i7 => i7.SB),
                                         Avg = (Double)(((Double)batting.Sum(i9 => i9.H)) / ((Double)batting.Sum(i10 => i10.AB)))
                                     };
                        foreach (var s in master)
                        {
                            //hofDbls.SetValue((double)s.Doubles);
                            hofDbls.Add((double)s.Doubles);
                            hofTrips.Add((double)s.Triples);
                            hofHits.Add((double)s.Hits);
                            hofABS.Add((double)s.AB);
                            hofHRS.Add((double)s.HomeRuns);
                            hofRuns.Add((double)s.Runs);
                            hofRBIS.Add((double)s.RBI);
                            hofSBS.Add((double)s.StolenBases);
                            hofAVG.Add((double)s.Avg);
                            count++;
                        }
                    }
                }

                List<double>[] hofDbls2 = comm.Gather(hofDbls, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofDbls3 in hofDbls2)
                    {
                        for (int i = 0; i < hofDbls3.Count; i++)
                        {
                            double newH = (double)hofDbls3[i];
                            nhofDbls.Add(newH);
                        }
                    }
                }

                List<double>[] hofTrips2 = comm.Gather(hofTrips, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofTrips3 in hofTrips2)
                    {
                        for (int i = 0; i < hofTrips3.Count; i++)
                        {
                            double newH = (double)hofTrips3[i];
                            nhofTrips.Add(newH);
                        }
                    }
                }

                List<double>[] hofHits2 = comm.Gather(hofHits, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofHits3 in hofHits2)
                    {
                        for (int i = 0; i < hofHits3.Count; i++)
                        {
                            double newH = (double)hofHits3[i];
                            nhofHits.Add(newH);
                        }
                    }
                }

                List<double>[] hofABS2 = comm.Gather(hofABS, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofABS3 in hofABS2)
                    {
                        for (int i = 0; i < hofABS3.Count; i++)
                        {
                            double newH = (double)hofABS3[i];
                            nhofABS.Add(newH);
                        }
                    }
                }

                List<double>[] hofHRS2 = comm.Gather(hofHRS, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofHRS3 in hofHRS2)
                    {
                        for (int i = 0; i < hofHRS3.Count; i++)
                        {
                            double newH = (double)hofHRS3[i];
                            nhofHRS.Add(newH);
                        }
                    }
                }

                List<double>[] hofRuns2 = comm.Gather(hofRuns, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofRuns3 in hofRuns2)
                    {
                        for (int i = 0; i < hofRuns3.Count; i++)
                        {
                            double newH = (double)hofRuns3[i];
                            nhofRuns.Add(newH);
                        }
                    }
                }

                List<double>[] hofRBIS2 = comm.Gather(hofRBIS, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofRBIS3 in hofRBIS2)
                    {
                        for (int i = 0; i < hofRBIS3.Count; i++)
                        {
                            double newH = (double)hofRBIS3[i];
                            nhofRBIS.Add(newH);
                        }
                    }
                }

                List<double>[] hofSBS2 = comm.Gather(hofSBS, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofSBS3 in hofSBS2)
                    {
                        for (int i = 0; i < hofSBS3.Count; i++)
                        {
                            double newH = (double)hofSBS3[i];
                            nhofSBS.Add(newH);
                        }
                    }
                }

                List<double>[] hofAVG2 = comm.Gather(hofAVG, 0);
                if (comm.Rank == 0)
                {
                    foreach (List<double> hofAVG3 in hofAVG2)
                    {
                        for (int i = 0; i < hofAVG3.Count; i++)
                        {
                            double newH = (double)hofAVG3[i];
                            nhofAVG.Add(newH);
                        }
                    }
                }

                double hofDblsStd = 0; double hofHRSStd = 0; double hofAVGStd = 0;
                double hofDblsMean = 0; double hofHRSMean = 0; double hofAVGMean = 0;
                double hofTripsStd = 0; double hofRunsStd = 0;
                double hofTripsMean = 0; double hofRunsMean = 0;
                double hofHitsStd = 0; double hofRBISStd = 0;
                double hofHitsMean = 0; double hofRBISMean = 0;
                double hofABSStd = 0; double hofSBSStd = 0;
                double hofABSMean = 0; double hofSBSMean = 0;

                if (comm.Rank == 0)
                {
                    //Console.WriteLine("{0},{1},{2},{3},{4}", totalDoubles, totalTriples, totalHits, totalHomeRuns, count);
                    //double hofDblsStd = newPrg.getStd(hofDbls2);
                    hofDblsStd = newPrg.getStd(nhofDbls);//newPrg.getLStd(hofDbls2);
                    hofDblsMean = newPrg.getMean(nhofDbls);

                    hofTripsStd = newPrg.getStd(nhofTrips);
                    hofTripsMean = newPrg.getMean(nhofTrips);

                    hofHitsStd = newPrg.getStd(nhofHits);
                    hofHitsMean = newPrg.getMean(nhofHits);

                    hofABSStd = newPrg.getStd(nhofABS);
                    hofABSMean = newPrg.getMean(nhofABS);

                    hofHRSStd = newPrg.getStd(nhofHRS);
                    hofHRSMean = newPrg.getMean(nhofHRS);

                    hofRunsStd = newPrg.getStd(nhofRuns);
                    hofRunsMean = newPrg.getMean(nhofRuns);

                    hofRBISStd = newPrg.getStd(nhofRBIS);
                    hofRBISMean = newPrg.getMean(nhofRBIS);

                    hofSBSStd = newPrg.getStd(nhofSBS);
                    hofSBSMean = newPrg.getMean(nhofSBS);

                    hofAVGStd = newPrg.getStd(nhofAVG);
                    hofAVGMean = newPrg.getMean(nhofAVG);
                    //End

                    //Console.WriteLine("{0} {1}", hofDblsStd, hofDblsMean);
                    Console.WriteLine("Total records {0}", count);
                    Console.WriteLine("end printing--------");
                    //Start time
                }
                DateTime endTime = DateTime.Now;
                DateTime start = DateTime.Now;
                var plyList = from bttr in db.Battings
                              where (from fldgs in db.Fieldings
                                     where !fldgs.POS.Equals('P')
                                     group fldgs by fldgs.playerID into fld
                                     where fld.Count() > 10
                                     select fld.Key).Contains(bttr.playerID)
                                      &&
                                      !(from mst in db.Masters
                                        join hoff in db.HallOfFames on mst.hofID equals hoff.hofID
                                        select mst.hofID).Contains(bttr.playerID)
                              orderby bttr.playerID
                              group bttr by bttr.playerID into batter
                              select new
                              {
                                  ID = batter.Key
                              };


                Console.WriteLine("start for new ID");
                double ctagain = 0;
                foreach (var qq in plyList)
                {
                    var mastrB = from b in db.Battings
                                 join m in db.Masters on b.playerID equals m.playerID
                                 where (qq.ID == b.playerID)
                                 group b by b.playerID into batting
                                 select new
                                 {
                                     Id = batting.Key,
                                     Doubles = batting.Average(i => i._2B),
                                     Triples = batting.Average(i2 => i2._3B),
                                     Hits = batting.Average(i3 => i3.H),
                                     AB = batting.Average(i8 => i8.AB),
                                     HomeRuns = batting.Average(i4 => i4.HR),
                                     Runs = batting.Average(i5 => i5.R),
                                     RBI = batting.Average(i6 => i6.RBI),
                                     StolenBases = batting.Average(i7 => i7.SB),
                                     Avg = (Double)(((Double)batting.Sum(i9 => i9.H)) / ((Double)batting.Sum(i10 => i10.AB)))
                                 };
                    foreach (var sq in mastrB)
                    {
                        zValueDoubles = newPrg.getZScore((Double)sq.Doubles, hofDblsMean, hofDblsStd);
                        zValueTrips = newPrg.getZScore((Double)sq.Triples, hofTripsMean, hofTripsStd);
                        zValueHits = newPrg.getZScore((Double)sq.Hits, hofHitsMean, hofHitsStd);
                        zValueABS = newPrg.getZScore((Double)sq.AB, hofABSMean, hofABSStd);
                        zValueHRS = newPrg.getZScore((Double)sq.HomeRuns, hofHRSMean, hofHRSStd);
                        zValueRuns = newPrg.getZScore((Double)sq.Runs, hofRunsMean, hofRunsStd);
                        zValueRBIS = newPrg.getZScore((Double)sq.RBI, hofRBISMean, hofRBISStd);
                        zValueSBS = newPrg.getZScore((Double)sq.StolenBases, hofSBSMean, hofSBSStd);
                        zValueAVG = newPrg.getZScore((Double)sq.Avg, hofAVGMean, hofAVGStd);

                        double totals = ((zValueDoubles + zValueTrips + zValueHits + zValueABS + zValueHRS + zValueRuns + zValueRBIS + zValueSBS + zValueAVG) / 9);
                        zscore.Add(sq.Id, totals);

                        
                        //Console.WriteLine("User: {0} ZValue: {1}", sq.Id, zValueDoubles);
                    }
                }
                Dictionary<string, double>[] zscore2 = comm.Gather(zscore, 0);
                System.Collections.IEnumerator zscore5 = zscore2.GetEnumerator();
                while ((zscore5.MoveNext()) && (zscore5.Current != null))
                {
                    Console.WriteLine("{0}", zscore5.Current);
                }
                /*Dictionary<string, double> zscore4 = new Dictionary<string, double>();
                foreach (Dictionary<string, double> zscore3 in zscore2)
                {
                    for (int i = 0; i < zscore3.Count; i++)
                    {
                        string id = zscore3.ElementAt(i).Key;
                        double totals = zscore3.ElementAt(i).Value;
                        zscore4.Add(id, totals);
                    }
                }
                if (comm.Rank == 0)
                {
                    Dictionary<string, double> newDTZScore = newPrg.SortDictionary(zscore4);
                    foreach (KeyValuePair<string, double> item in newDTZScore.OrderBy(key => key.Value))
                    {
                        if (item.Value >= 0)
                        {
                            ctagain++;
                            Console.WriteLine("{0},{1}", item.Key, item.Value);
                        }
                    }
                }*/

                //endtime
                DateTime end = DateTime.Now;
                TimeSpan duration1 = endTime - startTime;
                TimeSpan duration2 = end - start;
                Console.WriteLine("Time to calculate std and mean for hall of fame players {0}, {1}", duration1.TotalMinutes, duration1.TotalSeconds);
                Console.WriteLine("Time to calculate zscore for all batters {0}, {1}", duration2.TotalMinutes, duration2.TotalSeconds);
                Console.WriteLine("ct for new Id {0}", ctagain);



                Console.ReadLine();

                //results.ToList();
            }
        }
    }
}